﻿#region Imports
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using AddressBox.Models;
using AddressBox.Util;
using BulkRenamer.Util;
using BulkRenamer.Util.Enums;
using BulkRenamer.Util.Extensions;
#endregion

#region AutoCompleteBox
// xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
// C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client\System.Windows.Controls.dll
#endregion

namespace AddressBox
{
    /// <summary>
    /// Interaction logic for AddressBox.xaml
    /// </summary>
    public partial class AddressBox : UserControl
    {
        #region Declarations
        /// <summary>
        /// Default tooltip value for invalid path
        /// </summary>
        const string sNotSelected = "<Not selected>";
        //const string sCheckBoxNamePrefix = "chkExtnFilter"; // RKD
        /// <summary>
        /// Wildcard character for search
        /// </summary>
        const char chrWildcard = '%';
        #endregion

        #region Constructors
        /// <summary>
        /// Default constructor
        /// </summary>
        public AddressBox()
        {
            InitializeComponent();
            btnFetchDirUp.IsEnabled = btnFetchDirDown.IsEnabled = btnFetchDirPrev.IsEnabled = btnFetchDirNext.IsEnabled = false;
        }
        #endregion

        #region Properties
        public string SelectedBasePath { get; set; }

        public ObservableCollection<IdNameValueMember> AllPathSuggestions { get; set; }

        public new int Height { get { return 40; } }
        #endregion

        #region Events
        private void txtBasePath_TextChanged(object sender, TextChangedEventArgs e)
        {
            #region File load
            SelectedBasePath = txtBasePath.Text;

            string tooltipText = Utilities.ValidatePath(SelectedBasePath, ePathValidation.Directory) ? SelectedBasePath.Trim() : sNotSelected;
            txtbTooltipValue.Text = "Selected base path: \r\n   " + tooltipText;

            string tmpPath = "";
            EvaluateDirectory(eFetchTypes.All, SelectedBasePath, ref tmpPath);
            //if (chkAutoLoad.Checked) btnLoadFiles_Click(sender, e);
            #endregion

            #region Path suggestion
            PopulatePathSuggestion(txtBasePath.Text);
            if (cmbPathSuggestion.HasItems && txtBasePath.IsFocused) cmbPathSuggestion.IsDropDownOpen = true;
            #endregion
        }

        private void btnBrowsePath_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            //OpenFileDialog dlgOpenTargetFile = new OpenFileDialog
            //{
            //    Title = "Select base directory..",
            //    Multiselect = true,
            //    CheckFileExists = true,
            //    CheckPathExists = true,
            //    RestoreDirectory = true
            //};
            //
            //dlgOpenTargetFile.InitialDirectory = !Utilities.IsPathFormatValid(txtBasePath.Text) ? sDefaultPath
            //    : Directory.Exists(txtBasePath.Text) ? txtBasePath.Text : sDefaultPath;
            //
            //string sDialogFilters = "";
            //if (chkAnyExtn.Checked)
            //    sDialogFilters = FormatDialogFilters(new IdNameValueMember { Name = sAllExtn, Value = "*.*" });
            //else
            //{
            //    foreach (IdNameValueMember idval
            //       in AllExtn.Where(idval => !String.IsNullOrEmpty((string)idval.Name) & (string)idval.Name == SelectedExtn)
            //               .OrderBy(idval => (int)idval.Id == 0 ? 1 : 0).ThenBy(idval => (int)idval.Id))
            //    {
            //        sDialogFilters += FormatDialogFilters(idval);
            //    }
            //}
            //
            //dlgOpenTargetFile.Filter = sDialogFilters.TrimEnd('|');
            //dlgOpenTargetFile.FilterIndex = !String.IsNullOrEmpty(SelectedExtn) || chkAnyExtn.Checked ? 1
            //    : dlgOpenTargetFile.Filter.Split('|').Select(flt => flt.Replace("*.", "")).ToList().IndexOf(SelectedExtn) / 2 + 1;
            //dlgOpenTargetFile.DefaultExt = chkAnyExtn.Checked ? "" : SelectedExtn;
            //
            //if (dlgOpenTargetFile.ShowDialog() == DialogResult.OK)
            //{
            //    txtBasePath.Text = Path.GetDirectoryName(dlgOpenTargetFile.FileName);
            //    if (chkAutoLoad.Checked) btnLoadFiles_Click(sender, e);
            //}
        }

        private void Suggestion_Navigation(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape) cmbPathSuggestion.IsDropDownOpen = false;
            else
            {
                if (e.Key == Key.Up)
                {
                    // if (!cmbPathSuggestion.HasItems) cmbPathSuggestion.IsDropDownOpen = false;




                    //else
                    //{
                    //    if (cmbPathSuggestion.SelectedIndex==0)
                    //        cmbPathSuggestion.SelectedIndex --;
                    //    else cmbPathSuggestion.SelectedIndex = 0;
                    //}
                }
                else if (e.Key == Key.Down)
                {
                    //if (((Control)sender).Name == txtBasePath.Name)
                    //{
                    //else
                    //    if (cmbPathSuggestion.HasItems) cmbPathSuggestion.SelectedIndex = 0;

                    //}
                    //else if (((Control)sender).Name == cmbPathSuggestion.Name)
                    //{
                    if (cmbPathSuggestion.HasItems)
                    {
                        if (!cmbPathSuggestion.IsDropDownOpen)
                            cmbPathSuggestion.IsDropDownOpen = true;

                        //if (cmbPathSuggestion.SelectedIndex < cmbPathSuggestion.Items.Count - 1)
                        //    cmbPathSuggestion.SelectedIndex++;
                        //else txtBasePath.Focus(); // cmbPathSuggestion.SelectedIndex = 0;
                    } //}
                }

                BrowseList(e.Key, true);
            }
        }

        private void cmbPathSuggestion_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape || e.Key == Key.Left) txtBasePath.Focus();
            else
            {
                BrowseList(e.Key);
                //cmbPathSuggestion.IsDropDownOpen = false;
                //if ((e.Key == Key.Up && cmbPathSuggestion.SelectedIndex > 0) || (e.Key == Key.Down && cmbPathSuggestion.SelectedIndex <= cmbPathSuggestion.Items.Count - 1))
                //    cmbPathSuggestion.IsDropDownOpen = true;
                //else { }
            }
        }

        private void btnFetchDirectory_Click(object sender, RoutedEventArgs e)
        {
            eFetchTypes fetchType = Enum.GetValues(typeof(eFetchTypes)).Cast<eFetchTypes>()
                .Where(ftype => ftype.ToString() == GetEnumFromButton(sender)).First();

            FetchDirectory(fetchType, sender, e);
            txtBasePath.Focus();
        }
        #endregion

        #region Methods
        /// <summary>
        /// Evaluates a directory for Prev/Next/Up/Down functions
        /// </summary>
        /// <param name="fetchType">Fetch type</param>
        /// <param name="srcPath">Path to validate against</param>
        /// <param name="destPath">Path (updated, only when valid)
        /// <para>Note: this passed ByRef</para></param>
        /// <returns></returns>
        public bool EvaluateDirectory(eFetchTypes fetchType, string srcPath, ref string destPath)
        {
            ObservableCollection<string> allDirectories = new ObservableCollection<string>();
            int currDirectoryIndex = -1;
            bool pathValidations = false;
            bool result = false;

            if (fetchType != eFetchTypes.All)
            {
                destPath = srcPath;
                pathValidations = Utilities.ValidatePath(srcPath, ePathValidation.Directory);

                if (pathValidations)
                {
                    if (fetchType == eFetchTypes.Prev || fetchType == eFetchTypes.Next)
                    {
                        if (!Utilities.IsNull(Directory.GetParent(srcPath)))
                        {
                            allDirectories = new ObservableCollection<string>(
                                Utilities.GetValidDirectories(Directory.GetParent(srcPath).FullName));
                            currDirectoryIndex = allDirectories.IndexOf(srcPath);
                        }
                        else
                        {
                            allDirectories = new ObservableCollection<string>(
                                DriveInfo.GetDrives().Where(drv => drv.IsReady).Select(drv => drv.RootDirectory.Root.FullName));
                            currDirectoryIndex = allDirectories.IndexOf(srcPath);
                        }
                    }
                }
            }

            switch (fetchType)
            {
                case eFetchTypes.Prev:
                    btnFetchDirPrev.IsEnabled = result = (pathValidations && currDirectoryIndex > 0);
                    if (result) destPath = allDirectories.ElementAt(currDirectoryIndex - 1);
                    break;

                case eFetchTypes.Next:
                    btnFetchDirNext.IsEnabled = result = (pathValidations && currDirectoryIndex + 1 < allDirectories.Count());
                    if (result) destPath = allDirectories.ElementAt(currDirectoryIndex + 1);
                    break;

                case eFetchTypes.Up:
                    btnFetchDirUp.IsEnabled = result = (pathValidations && !Utilities.IsNull(Directory.GetParent(srcPath)) && srcPath.ToLower() != Directory.GetDirectoryRoot(srcPath).ToLower());
                    if (result) destPath = Directory.GetParent(srcPath).FullName;
                    break;

                case eFetchTypes.Down:
                    btnFetchDirDown.IsEnabled = result = (pathValidations && Utilities.GetValidDirectories(srcPath).Any());
                    if (result) destPath = Utilities.GetValidDirectories(srcPath).First();
                    break;

                case eFetchTypes.All:
                    foreach (eFetchTypes ftype in Enum.GetValues(typeof(eFetchTypes)).Cast<eFetchTypes>())
                        if (ftype != fetchType) EvaluateDirectory(ftype, SelectedBasePath, ref destPath);
                    break;

                default:
                    result = false;
                    break;
            }

            return result;
        }

        private void PopulatePathSuggestion(string searchText)
        {
            ObservableCollection<IdNameValueMember> allPathSuggestions
                = new ObservableCollection<IdNameValueMember>(FetchPathSuggestion(searchText));
            AllPathSuggestions = allPathSuggestions;

            cmbPathSuggestion.ItemsSource = AllPathSuggestions;
        }

        private ObservableCollection<IdNameValueMember> FetchPathSuggestion(string path)
        {
            if (String.IsNullOrEmpty(path))
                return new ObservableCollection<IdNameValueMember>();

            ObservableCollection<string> allPath = new ObservableCollection<string>();
            if (path.ToCharArray().Last() == Path.DirectorySeparatorChar && Utilities.ValidatePath(path, ePathValidation.Directory))
                allPath = new ObservableCollection<string>(Utilities.GetValidDirectories(path.TrimEnd(Path.DirectorySeparatorChar)));
            else
                if (path.Contains(Path.DirectorySeparatorChar))
                {
                    string parent = path.TrimAndTake(path.LastIndexOf(Path.DirectorySeparatorChar), eTrimDirection.Left);
                    string searchText = Utilities.GetDirectoryNameFull(path).ToLower();

                    allPath = new ObservableCollection<string>(Utilities.GetValidDirectories(parent + Path.DirectorySeparatorChar));

                    if (!String.IsNullOrEmpty(searchText))
                    {
                        if (!searchText.Contains(chrWildcard.ToString()))
                            allPath = new ObservableCollection<string>(
                                allPath.Where(dir => Utilities.GetDirectoryNameFull(dir).ToLower().StartsWith(searchText.Trim(chrWildcard))));
                        else if (searchText.StartsWith(chrWildcard.ToString()) && searchText.EndsWith(chrWildcard.ToString()))
                            allPath = new ObservableCollection<string>(
                                allPath.Where(dir => Utilities.GetDirectoryNameFull(dir).ToLower().Contains(searchText.Trim(chrWildcard))));
                        else if (searchText.StartsWith(chrWildcard.ToString()))
                            allPath = new ObservableCollection<string>(
                                allPath.Where(dir => Utilities.GetDirectoryNameFull(dir).ToLower().StartsWith(searchText.Trim(chrWildcard))));
                        else if (searchText.EndsWith(chrWildcard.ToString()))
                            allPath = new ObservableCollection<string>(
                                allPath.Where(dir => Utilities.GetDirectoryNameFull(dir).ToLower().EndsWith(searchText.Trim(chrWildcard))));
                    }
                }

            return new ObservableCollection<IdNameValueMember>(
                allPath.Select(dir => new IdNameValueMember { Id = dir }));
        }

        /// <summary>
        /// Fetches directory based on specified direction
        /// </summary>
        /// <param name="fetchType">Fetch type</param>
        /// <param name="sender">Sender</param>
        /// <param name="e">EventArgs</param>
        private void FetchDirectory(eFetchTypes fetchType, object sender, EventArgs e)
        {
            string tmpSelectedBasePath = SelectedBasePath;
            if (EvaluateDirectory(fetchType, SelectedBasePath, ref tmpSelectedBasePath))
            {
                txtBasePath.Text = tmpSelectedBasePath;
                //if (chkAutoLoad.Checked) btnLoadFiles_Click(sender, e);
            }
        }

        private void BrowseList(Key keyPressed, bool isCallFromTextBox = false)
        {
            if (keyPressed == Key.Return)
                if (!Utilities.IsNull(cmbPathSuggestion.SelectedItem))
                    if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                    {
                        txtBasePath.Text = (string)((IdNameValueMember)cmbPathSuggestion.SelectedItem).Id;
                        txtBasePath.Focus(); SendKeys.Send(Key.End);
                    }

            if (!cmbPathSuggestion.HasItems || (keyPressed != Key.Down && keyPressed != Key.Up)) return;

            if (keyPressed == Key.Down)
            {
                if (cmbPathSuggestion.SelectedIndex < cmbPathSuggestion.Items.Count - 1)
                    cmbPathSuggestion.SelectedIndex++;
                else
                {
                    if (isCallFromTextBox) cmbPathSuggestion.SelectedIndex = 0;
                    else txtBasePath.Focus();
                }
            }
            else if (keyPressed == Key.Up)
            {
                if (cmbPathSuggestion.SelectedIndex > 0)
                {
                    cmbPathSuggestion.SelectedIndex--;
                    cmbPathSuggestion.IsDropDownOpen = false;
                    cmbPathSuggestion.IsDropDownOpen = true;
                }
                else
                {
                    if (isCallFromTextBox) cmbPathSuggestion.SelectedIndex = cmbPathSuggestion.Items.Count - 1;
                    else txtBasePath.Focus();
                }
            }

            if (isCallFromTextBox || !txtBasePath.IsFocused)
            {
                RefreshComboDropdown();
            }
        }

        private void RefreshComboDropdown()
        {
            cmbPathSuggestion.IsDropDownOpen = false;
            cmbPathSuggestion.IsDropDownOpen = true;
        }

        private string GetEnumFromButton(object btnFetchDir)
        {
            return ((Button)btnFetchDir).Name.Replace("btnFetchDir", "");
        }
        #endregion
    }
}
